﻿using System;

namespace NodeJS
{
    /// <summary>
    /// When an EventEmitter instance experiences an error, the typical action is to emit an 'error' event. Error events are treated as a special case in node. If there is no listener for it, then the default action is to print a stack trace and exit the program.
    /// All EventEmitters emit the event 'newListener' when new listeners are added and 'removeListener' when a listener is removed.
    /// </summary>
    [ImportClass("require('events')", "EventEmitter")]
    public class EventEmitter
    {
        [EvalAtCompile(Value = "newListener")]
        public const NodeEvent NEW_LISTENER = null;
        [EvalAtCompile(Value = "removeListener")]
        public const NodeEvent REMOVE_LISTENER = null;

        /// <summary>
        /// Return the number of listeners for a given event.
        /// </summary>
        /// <param name="emitter"></param>
        /// <param name="evt"></param>
        /// <returns></returns>
        public static int ListenerCount(EventEmitter emitter, string evt)
        {
            return 0;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter AddListener<T>(NodeEvent evt, Action<T> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter AddListener<T1, T2>(NodeEvent evt, Action<T1, T2> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter AddListener<T1, T2, T3>(NodeEvent evt, Action<T1, T2, T3> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <typeparam name="T4"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter AddListener<T1, T2, T3, T4>(NodeEvent evt, Action<T1, T2, T3, T4> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter On(NodeEvent evt, Action listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter On<T>(NodeEvent evt, Action<T> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter On<T1, T2>(NodeEvent evt, Action<T1, T2> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter On<T1, T2, T3>(NodeEvent evt, Action<T1, T2, T3> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a listener to the end of the listeners array for the specified event.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <typeparam name="T4"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter On<T1, T2, T3, T4>(NodeEvent evt, Action<T1, T2, T3, T4> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a one time listener for the event. This listener is invoked only the next time the event is fired, after which it is removed.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter Once<T>(NodeEvent evt, Action<T> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a one time listener for the event. This listener is invoked only the next time the event is fired, after which it is removed.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter Once<T1, T2>(NodeEvent evt, Action<T1, T2> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a one time listener for the event. This listener is invoked only the next time the event is fired, after which it is removed.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter Once<T1, T2, T3>(NodeEvent evt, Action<T1, T2, T3> listener)
        {
            return this;
        }

        /// <summary>
        /// Adds a one time listener for the event. This listener is invoked only the next time the event is fired, after which it is removed.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <typeparam name="T4"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter Once<T1, T2, T3, T4>(NodeEvent evt, Action<T1, T2, T3, T4> listener)
        {
            return this;
        }

        /// <summary>
        /// Remove a listener from the listener array for the specified event. Caution: changes array indices in the listener array behind the listener.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter RemoveListener<T>(NodeEvent evt, Action<T> listener)
        {
            return this;
        }

        /// <summary>
        /// Remove a listener from the listener array for the specified event. Caution: changes array indices in the listener array behind the listener.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter RemoveListener<T1, T2>(NodeEvent evt, Action<T1, T2> listener)
        {
            return this;
        }

        /// <summary>
        /// Remove a listener from the listener array for the specified event. Caution: changes array indices in the listener array behind the listener.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter RemoveListener<T1, T2, T3>(NodeEvent evt, Action<T1, T2, T3> listener)
        {
            return this;
        }

        /// <summary>
        /// Remove a listener from the listener array for the specified event. Caution: changes array indices in the listener array behind the listener.
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <typeparam name="T3"></typeparam>
        /// <typeparam name="T4"></typeparam>
        /// <param name="evt"></param>
        /// <param name="listener"></param>
        /// <returns></returns>
        public EventEmitter RemoveListener<T1, T2, T3, T4>(NodeEvent evt, Action<T1, T2, T3, T4> listener)
        {
            return this;
        }

        /// <summary>
        /// Removes all listeners, or those of the specified event.
        /// </summary>
        /// <param name="evt"></param>
        /// <returns></returns>
        public EventEmitter RemoveAllListeners(NodeEvent evt = null)
        {
            return this;
        }

        /// <summary>
        /// By default EventEmitters will print a warning if more than 10 listeners are added for a particular event. This is a useful default which helps finding memory leaks. Obviously not all Emitters should be limited to 10. This function allows that to be increased.
        /// </summary>
        /// <param name="n">Set to zero for unlimited.</param>
        public void SetMaxListeners(int n)
        {
        }

        /// <summary>
        /// Returns an array of listeners for the specified event.
        /// </summary>
        /// <param name="evt"></param>
        /// <returns></returns>
        public object[] Listeners(NodeEvent evt)
        {
            return null;
        }

        /// <summary>
        /// Execute each of the listeners in order with the supplied arguments.
        /// </summary>
        /// <param name="evt"></param>
        /// <param name="args"></param>
        /// <returns>Returns true if event had listeners, false otherwise.</returns>
        public bool Emit(NodeEvent evt, params object[] args)
        {
            return false;
        }
    }
}
